home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mesolore
/
Mesolore - Disc 1.iso
/
pc
/
data
/
Buttons.cst
/
00185_Script_Custom Scrollbar
< prev
next >
Wrap
Text File
|
2001-04-13
|
36KB
|
1,039 lines
-- DESCRIPTION --
on getBehaviorDescription me
return "¼
CUSTOM SCROLL BAR"&RETURN&RETURN&"¼
Create dynamic scrollbars with your own artwork. Such scrollbars are not ¼
Direct-To-Stage, so other sprites can appear over the top of them."&¼
RETURN&RETURN&"¼
You will need to create four graphic members:"&RETURN&"¼
+ up arrow"&RETURN&"¼
+ down arrow"&RETURN&"¼
+ dragger"&RETURN&"¼
+ backing bar"&RETURN&RETURN&"¼
You may wish to use two additional members, to indicate that the arrow buttons ¼
have been pressed:"&RETURN&"¼
+ up arrow (pressed state)"&RETURN&"¼
+ down arrow (pressed state)"&RETURN&RETURN&"¼
Place the four standard members on the Stage, and drop this behavior onto each ¼
of them. Choose how the current sprite is to act in the appropriate pop-up ¼
menu in the Behavior Parameters dialog."&RETURN&RETURN&"¼
For each element you can choose whether animations should continue in the ¼
background. This option will tend to slow both the animations and the ¼
scrolling process, especially if applied to the arrow buttons."&RETURN&RETURN&"¼
The various sprites will position themselves automatically to the right of the ¼
sprite-to-be-scrolled when the movie runs. They revert to their original ¼
positions when it stops. To avoid flashes, it would be a good idea to ¼
position them by hand in their intended positions."&RETURN&RETURN&"¼
If you use a border on your field members, the scrollbar will sit outside the ¼
border. Field box shadows are not recommended. You can always fake external ¼
borders and box shadows with shape members (this even gives you a choice of ¼
colors)."&RETURN&RETURN&"¼
To make authoring easier, this behavior will continue to work if you change ¼
EITHER the sprite channel OR the member in the chosen channel. If you change ¼
both, the behavior will no longer know what to scroll."&RETURN&RETURN&"¼
If you do change either the sprite or the member, and then reopen the Behavior ¼
Parameters dialog for one of the elements, this will put that behavior out of ¼
synch with the others. Simply reopen and close the Parameters dialogs for ¼
each of the other elements. If you do not do so, you will receive multiple ¼
alerts."&RETURN&RETURN&"¼
This behavior can be used to scroll both editable and non-editable Fields and ¼
Text members. For editable members, however, it does not automatically update ¼
the dragger position when the length of the text changes, nor does it make the ¼
editable member scroll automatically when the user drags the mouse to create ¼
a selection."&RETURN&RETURN&"¼
PERMITTED MEMBER TYPES:"&RETURN&PermittedMemberTypes (me)&RETURN&RETURN&"¼
PARAMETERS:"&RETURN&"¼
* Current sprite acts as (up|down arrow | dragger | bar)"&RETURN&"¼
* Scroll the member of <sprite>: <the member of sprite>"&RETURN&"¼
* Standard member (this should not need to be set)"&RETURN&"¼
* Member to display when arrow buttons are pressed"&RETURN&"¼
* Allow animations to continue"&RETURN&RETURN&"¼
PUBLIC METHODS"&RETURN&"¼
=> Scroll the text/field member to a given position"&RETURN&"¼
=> Swap the text/field member to be scrolled"&RETURN&"¼
=> Get the behavior reference"
end getBehaviorDescription
on getBehaviorTooltip me
return " ¼
Use 4 graphic members (dragger, bar, up and down arrows)"&RETURN&"¼
to create a dynamic scrollbar for Text or Field members."&RETURN&RETURN&"¼
Drop this behavior on each sprite separately."&RETURN&RETURN&"¼
Sprites can pass over the scrollbar and animations can"&RETURN&"¼
continue while the user scrolls."&RETURN&RETURN&"¼
The behavior accepts Lingo calls to:"&RETURN&"¼
+ set the scrolltop of the scrolled member to a given value."&RETURN&"¼
+ swap the current member of the sprite."
end getBehaviorTooltip
-- NOTES FOR DEVELOPERS
-- This is the most complex behavior I have written for the Behavior Library.
-- I have included in one script all the handlers necessary to deal with each
-- of the four elements of a scroll bar.
--
-- In practice, this one script works as four separate behaviors. Each element
-- is identified by its myScrollRole (upArrow, downArrow, dragger or bar). The
-- behavior acts differently for each myScrollRole. Many handlers are divided
-- into section by a "case myScrollRole of" statement.
-- INSTALLATION
-- Initializing the 4 behaviors cannot be done all at once on beginSprite
-- because the behaviors on the other sprites may not exist. To get round
-- this, I set a myState property to 0 in the StartInstallation handler
-- (on beginSprite). The first prepareFrame (which is sent once all behaviors
-- in the current frame have been instanciated) sees that "myState + 0 = 0"
-- (or FALSE) and calls the FinishInstallation handler.
-- Why "myState + 0"? Because once the installation is finished, myState is
-- set to #done. This is a symbol. A symbol is simply an integer with a
-- special tag. Adding zero to a symbol gives you access to the integer
-- itself. Later, when the prepareFrame handler encounters "#done + 0" it
-- evaluates this as a positive integer (or TRUE) and doesn't botherd to
-- reinstall the elements.
-- This technique is excessively fast: it slows down the following
-- prepareFrames by something in the order of a millionth of a second.
-- Installation itself is a three step-process.
-- First: the behavior has to check if the sprite and member that it is to
-- scroll do actually appear where it expects to find them. The
-- ourScrolledElement property returned by the getPropertyDescriptionList
-- handler is a double-barreled affair: "sprite X:field(member Y of castLib Z)".
-- If sprite X contains a Field or Text member, the behavior assumes that this
-- is the right one, and adopts it as myScrolledMember. If not, it sets out to
-- look for (member Y of castLib Z), via the FindSprite handler. If it finds
-- this member in one of the sprites in the frame, then it adopts the new
-- sprite as myScrolledSprite. If not, it warns the author (4 times, once for
-- each behavior).
-- Second: the current behavior has to check if all the others are present.
-- The Initialize handler has already prepared a list of all behaviors which
-- treat the same sprite and/or member: ourControlList. The CheckControl
-- handler ensures that this list contains one behavior for each control
-- element... and only one.
-- Third: the sprite to which the behavior is attached has to be placed
-- correctly beside the sprite it is to scroll. This is most complex for the
-- Dragger sprite, since it must be placed in accordance with the current
-- scrollTop of myScrolledMember.
-- The scrolling itself is always carried out by the behavior attached to the
-- dragger. The Move and MoveBar handlers (which deal with clicks on the arrow
-- buttons and on the backing bar) end with a...
--
-- call (#SetDraggerShift, ourControlList.dragger)
--
-- ... command. The bar behavior must in addition ask the dragger where it now
-- is, using "call (#GetDraggerData, ourControlList.dragger)", so as to update its
-- myActiveZone.
-- EXTERNAL LINGO CALLS
-- * CustomScrollbar_SetScroll me, theScroll
-- If you use standard Lingo to set the scrollTop of myScrolledMember at
-- runtime, the dragger position will not update until the scroll bar is next
-- used. Use this call to tell the dragger to do all the work for you
-- * CustomScrollbar_SwapMember me, newMember, currentMemberOrSprite
-- If you use standard Lingo to swap the member of myScrolledSprite at runtime,
-- the behaviors will continually happily to scroll the member which is now
-- off-stage. Use this call to tell one of the behaviors do the swapping for
-- you.
-- * CustomScrollbar_GetReference me, memberOrSprite, controlOrList
-- Using sendAllSprites with one of the above messages will ensure that the
-- job gets done... four times, once by each behavior that makes up the
-- scroll bar. If you call one of the behaviors directly, the command will be
-- executed just once. But first you must get an object reference to the
-- behavior in question. The following syntax is the simplest:
--
-- scrollRef = sendAllSprites (#CustomScrollbar_GetReference, sprite X)
--
-- This will give you a reference to the behavior on the highest sprite which
-- controls the scrolling of sprite X.
-- More details on using these external calls are given in the handlers
-- themselves.
-- HISTORY --
-- 27 October 1998: written for the D7 Behaviors Palette by James Newton
-- 24 November 1998: vector shapes abandoned as permitted members
-- PROPERTIES --
property spriteNum
-- error checking
property getPDLError
-- author-defined parameters
property ourScrolledElement -- "<spriteNum>: <member>" of element to scroll
property myScrollRole -- sprite behaves as upArrow|downArrow|dragger|bar
property myActiveMember -- member which appears on mouseDown
property myStandardMember -- member which appears at all other times
property myMultiThreading -- updates on prepareFrame | while the mouseDown
-- internal properties
property mySprite
property myMember
property myRect -- rect to which all members must be set to fit
property myScrolledSprite -- sprite containing myScrolledMember
property myScrolledMember -- Text or Field member to scroll
property myActiveZone -- when mouse is in zone, scrolling continues
property myState -- #paused if mouse is outside myActiveZone
property myNextUpdate -- slows scrollByPage if necessary
-- properties specific to the dragger
property myZeroLoc -- loc of dragger when scrollTop = 0
property myDraggerShift -- vertical distance dwon from myZeroLoc
property myClickV -- vertical coordinate where the dragger was clicked
property myInterimShift -- value of shift while the dragger is being scrolled
property myMaxDraggerShift -- maximum value of dragger shift
-- property specific to the bar
property myPageScroll -- direction of scroll: #up or #down
-- properties shared between behaviors
property ourControlList -- list of behaviors which collaborate on scrollbar
property ourMaxScroll -- list shared by behaviors: [maximum scrollTop]
-- EVENT HANDLERS --
on beginSprite me
StartInstallation me
end beginSprite
on prepareFrame me
if not myState + 0 then FinishInstallation me -- First prepareFrame only
if myMultiThreading then UpdateScroll me
end prepareFrame
on mouseDown me
StartScroll me
end mouseDown
on mouseUp me
EndScroll me
end mouseUp
on mouseUpOutside me
EndScroll me
end mouseUpOutside
-- CUSTOM HANDLERS --
on StartInstallation me -- sent by beginSprite
mySprite = sprite(me.spriteNum)
myMember = mySprite.member
memberType = myMember.type
-- Error checking
if voidP (myScrollRole) then
ErrorAlert (me, #getPDL_Invalid)
end if
-- The member of the sprite may have changed since getPDL
myScrolledSprite = value (ourScrolledElement)
myScrolledMember = myScrolledSprite.member
-- Ensure that the scrolled sprite has not changed or moved
memberType = myScrolledMember.type
case memberType of
#field, #text: -- do nothing
otherwise
-- Try to find the expected member in another sprite
FindSprite (me)
end case
-- End of error checking
-- Calculate ideal sprite.rect
topLeft = point (myScrolledSprite.left, myScrolledSprite.top)
myRect = myScrolledSprite.rect - rect (topLeft, topLeft)
if memberType = #field then
if myScrolledMember.border then
myRect[1] = 1
end if
end if
-- Contact other sprites with the same behavior
ourMaxScroll = []
set ourControlList = [:]
sendAllSprites ¼
(¼
#CustomScrollbar_RollCall, ¼
ourScrolledElement, ¼
ourControlList, ¼
ourMaxScroll ¼
)
myState = 0 -- Check will be run on first prepareFrame
end StartInstallation
on FindSprite me -- sent by StartInstallation
-- Finds highest sprite containing the expected member to scroll
saveDelimiter = the itemDelimiter
the itemDelimiter = ":"
memberData = ourScrolledElement.item[2]
the itemDelimiter = saveDelimiter
delete memberData.word[1] -- Remove type information
delete memberData.char[1] -- Remove remaining space
memberData = value (memberData)
myScrolledMember = member (memberData)
scrollSprite = the lastChannel
repeat while scrollSprite
if sprite(scrollSprite).member = myScrolledMember then
-- We've found it!
myScrolledSprite = sprite (scrollSprite)
exit
end if
scrollSprite = scrollSprite - 1
end repeat
if not scrollSprite then
-- The expected member was not found
ErrorAlert me, #notScrollable, myScrolledSprite.member.type
end if
end FindSprite
on FinishInstallation me -- sent by first prepareFrame
-- Terminates the initialization process once all behaviors are in place
CheckControlList me
-- Place this sprite to the right of myScrolledSprite
InstallElement me
end FinishInstallation
on CheckControlList me -- sent by FinishInstallation
-- Checks if ourControlList contains one-and-only-one behavior with each role
checkList = duplicate (ourControlList)
roleList = [#upArrow, #downArrow, #dragger, #bar]
i = roleList.count()
repeat while i
theRole = roleList[i]
rolePosition = checkList.findPos (theRole)
if rolePosition then
roleList.deleteAt(i)
checkList.deleteAt (rolePosition)
end if
i = i - 1
end repeat
if checkList.count() then
ErrorAlert me, #extraControl, checkList.getPropAt (1)
end if
if roleList.count() then
ErrorAlert me, #missingControls, roleList
end if
end CheckControlList
on InstallElement me
-- sent by FinishInstallation on first prepareFrame, _SwapMembers
-- Places sprite next to myScrolledSprite and determines myActiveZone
scrollRoof = myScrolledSprite.top
scrollFloor = myScrolledSprite.bottom
scrollLeft = myScrolledSprite.right
if myScrolledMember.type = #field then
scrollLeft = scrollLeft - (myScrolledMember.border <> 0)
end if
case myScrollRole of
#upArrow:
mySprite.loc = point (scrollLeft, scrollRoof) + myMember.regPoint
myActiveZone = mySprite.rect
#downArrow:
locAdjust = myMember.regPoint - [0, mySprite.height]
rectAdjust = mySprite.rect - rect (mySprite.loc, mySprite.loc) ---òòò
mySprite.loc = point (scrollLeft, scrollFloor) + locAdjust
-- myActiveZone = mySprite.rect ùùùòòò
myActiveZone = rectAdjust + rect (mySprite.loc, mySprite.loc)
#bar:
barRoof = scrollRoof + call (#SpriteHeight, ourControlList.upArrow)
barRight = scrollLeft + call (#SpriteWidth, ourControlList.upArrow)
barFloor = scrollFloor - call (#SpriteHeight,ourControlList.downArrow)
mySprite.rect= rect (scrollLeft, barRoof, barRight, barFloor)
#dragger:
case myMember.type of
#vectorShape:
regOffset = (myMember.strokeWidth + 1) / 2
myMember.regPoint = point (regOffset, regOffset)
otherwise
myMember.regPoint = point (0,0)
end case
upHeight = call (#SpriteHeight, ourControlList.upArrow)
upWidth = call (#SpriteHeight, ourControlList.upArrow)
downHeight = call (#SpriteHeight, ourControlList.downArrow)
draggerRoof = scrollRoof + upHeight
myZeroLoc = point (scrollLeft, draggerRoof)
barRight = scrollLeft + upWidth
myActiveZone = rect (scrollLeft, scrollRoof, barRight, scrollFloor)
myActiveZone = inflate (myActiveZone, 32, 32)
arrowAdjust = upHeight + downHeight
pageHeight = myScrolledSprite.height
scrollHeight = pageHeight - arrowAdjust
draggerHeight = mySprite.Height
myMaxDraggerShift = 0 -- pre-emptive measure, in case dragger can't scroll
if scrollHeight < 0 then
-- Adjust length of myScrolledMember so that arrow buttons fit
minRect = myScrolledMember.rect
minRect[4] = arrowAdjust
myScrolledMember.rect = minRect
call (#InstallElement, ourControlList.bar)
end if
if scrollHeight < draggerHeight then
mySprite.loc = point (-999, -999)
else
-- Dragger can slide: set myMaxDraggerShift to reflect this
if myScrolledMember.type = #field then
theMargin = myScrolledMember.margin
theMargin = theMargin - theMargin mod 2
borderAdjust = (myScrolledMember.border * 2) + theMargin
else
borderAdjust = 0
end if
myMaxDraggerShift = scrollHeight - draggerHeight + borderAdjust
end if
ourMaxScroll[1] = GetMaxScroll (me)
SetDraggerShift me
end case
myState = #done
end InstallElement
on GetMaxScroll me
pageHeight = myScrolledSprite.height
if myScrolledMember.type = #text then
lastChar = myScrolledMember.char.count
textHeight = charPostoloc (myScrolledMember, lastChar)[2]
else
textHeight = myScrolledMember.height
end if
maxScroll = textHeight - pageHeight
if maxScroll < 1 then
return 0
else
return maxScroll
end if
end GetMaxScroll
-- SCROLLING --
on StartScroll me -- sent by mouseDown
-- StartInstallations properties for scroll and either performs one update
-- (if myMultiThreading is TRUE) or completes the operation (in repeat loop).
myState = #active
ourMaxScroll[1] = GetMaxScroll (me)
case myScrollRole of
#dragger:
-- Determine start of scroll
myClickV = the clickLoc[2]
myInterimShift = 0
#upArrow, #downArrow:
-- Swap members
mySprite.Member = myActiveMember
#bar:
-- Determine active zone
draggerData = call (#GetDraggerData, ourControlList.dragger)
if the clickLoc[2] < draggerData.top then
myActiveZone = GetBarZone (me, draggerData, #up)
else
myActiveZone = GetBarZone (me, draggerData, #down)
end if
end case
UpdateScroll me
if myMultiThreading then exit
-- Use a tight repeat loop to scroll as fast as possible
repeat while the mouseDown
UpdateScroll me
end repeat
end StartScroll
on UpdateScroll me -- sent by prepareFrame, StartScroll, ResumeScroll
-- Determines whether to pause or to scroll (and how to)
case myState of
#active:
if inside (the mouseLoc, myActiveZone) then
case myScrollRole of
#dragger: MoveDragger me
#upArrow: Move me, TRUE
#downArrow: Move me, FALSE
#bar: MoveBar me
end case
else
PauseScroll me
end if
#paused:
ResumeScroll me
end case
end UpdateScroll
on GetBarZone me, draggerData, pageScroll
-- Determines zone in which the mouse makes the text scroll by page
if not voidP (pageScroll) then
myPageScroll = pageScroll
end if
barZone = mySprite.rect
if myPageScroll = #up then
barZone [2] = myScrolledSprite.top
barZone [4] = draggerData.top
else
barZone [2] = draggerData.bottom
barZone [4] = myScrolledSprite.bottom
end if
return barZone
end GetBarZone
on MoveDragger me
-- Checks if the dragger has moved, and if so modifies scroll
newScroll = myDraggerShift + the mouseV - myClickV
newScroll = max (0, min (newScroll, myMaxDraggerShift))
if myInterimShift = newScroll then exit
myInterimShift = newScroll
SetTextScroll me, myInterimShift
end MoveDragger
on Move me, up
-- Scrolls one line up or down
if the ticks < myNextUpdate then exit
if voidP (myNextUpdate) then
-- Allow time for a quick single-line click
myNextUpdate = the ticks + 10
else
-- Don't scroll too fast
myNextUpdate = the ticks + 1
end if
if up then
if not myScrolledMember.scrollTop then exit
scrollByLine myScrolledMember, -1
else
maxScroll = ourMaxScroll[1]
if myScrolledMember.scrollTop = maxScroll then exit
scrollByLine myScrolledMember, 1
if myScrolledMember.scrollTop > maxScroll then
myScrolledMember.scrollTop = maxScroll
end if
end if
call (#SetDraggerShift, ourControlList.dragger)
end MoveUp
on MoveBar me, up
-- Scrolls one page up or down, leaving one previous line visible
if the ticks < myNextUpdate then exit
myNextUpdate = the ticks + 10 -- So as not to scroll too fast
if myPageScroll = #up then
scrollByPage (myScrolledMember, -1)
if myScrolledMember.scrollTop then
-- Leave previous top line visible at bottom
scrollByLine (myScrolledMember, 1)
end if
else -- down
maxScroll = ourMaxScroll[1]
if myScrolledMember.scrollTop = maxScroll then exit
scrollByPage (myScrolledMember, 1)
-- Leave previous bottom line visible at top
scrollByLine (myScrolledMember, -1)
if myScrolledMember.scrollTop > maxScroll then
myScrolledMember.scrollTop = maxScroll
end if
end if
call (#SetDraggerShift, ourControlList.dragger)
-- The area of the bar where the mouse should active has just got smaller
draggerData = call (#GetDraggerData, ourControlList.dragger)
myActiveZone = GetBarZone (me, draggerData)
end MoveBar
on PauseScroll me
-- Pauses the behavior when the mouse leaves myActiveZone
myState = #paused
case myScrollRole of
#dragger:
-- Revert to original scroll
SetTextScroll me, myDraggerShift
#upArrow, #downArrow:
-- Revert to original button image
mySprite.member = myStandardMember
if not myMultiThreading then
updateStage
end if
end case
end PauseScroll
on ResumeScroll me
-- Reactivates the behavior when the mouse returns to myActiveZone
myState = #active
case myScrollRole of
#upArrow, #downArrow:
mySprite.member = myActiveMember
end case
UpdateScroll me
end ResumeScroll
on EndScroll me
-- Tidies up after scroll is over, ready for the next one
case myScrollRole of
#dragger:
if not voidP (myInterimShift) then
if ourMaxScroll[1] then
myDraggerShift = myInterimShift
else
myDraggerShift = 0
ShiftDragger me, myDraggerShift
end if
end if
myInterimShift = void
#upArrow, #downArrow:
mySprite.member = myStandardMember
myNextUpdate = void
end case
myState = #done
end EndScroll
on SetTextScroll me, draggerShift
-- Calculates the scrollTop of the text, then sets it and moves the thum
if ourMaxScroll[1] then
textScroll = (draggerShift * ourMaxScroll[1]) / myMaxDraggerShift
myScrolledMember.scrollTop = textScroll
else
-- draggerShift = 0
end if
ShiftDragger me, draggerShift
end SetTextScroll
on SetDraggerShift me
-- Calculates the position of the dragger from myScrolledMember.scrollTop
maxScroll = ourMaxScroll[1]
if maxScroll then
textScroll = myScrolledMember.scrollTop
myDraggerShift = (textScroll * myMaxDraggerShift) / maxScroll
else
myDraggerShift = 0
end if
ShiftDragger me, myDraggerShift
end SetDraggerShift
on ShiftDragger me, draggerShift
if not myMaxDraggerShift then
-- Don't move dragger if there is no space to move it
exit
end if
mySprite.loc = myZeroLoc + [0, draggerShift]
updateStage
end ShiftDragger
-- PUBLIC METHODS (responses to #sendSprite, #sendAllSprites, #call) --
on CustomScrollbar_SetScroll me, theScroll
-- Allows an editable field to update its scrolltop via the #dragger behavior
-- Error check
case ilk (theScroll) of
#integer: -- nothing
#float: theScroll = integer (theScroll)
otherwise
return #invalidTypeError
end case
-- End of error check
theScroll = max (0, min (theScroll, ourMaxScroll[1]))
myScrolledMember.scrollTop = theScroll
call (#SetDraggerShift, ourControlList.dragger, theScroll)
end CustomScrollbar_SetScroll
on CustomScrollbar_SwapMember me, newMember, currentMemberOrSprite
-- Allows you to change the member of the scrolled sprite at runtime
-- newMember is a member reference, name or number. If you have a number of
-- custom scrollbars in the frame, then currentMemberOrSprite identifies
-- which member to change if you use a sendAllSprites messsage.
-- You can leave the currentMemberOrSprite parameter empty if you call a
-- specific behavior.
--
-- The following examples both set the member of sprite 1 to member 2.
-- The first example will actually do this four times, once for each
-- behavior that makes up the scrollbar:
--
-- sendAllSprites (#CustomScrollbar_SwapMember, member 2, sprite 1)
-- OR
-- scrollBehavior = sendAllSprites (#CustomScrollbar_GetReference, sprite 1)
-- call (#CustomScrollbar_SwapMember, scrollBehavior, member 2)
-- Error check
case ilk (newMember) of
#member: -- do nothing
#integer, #string:
memberExists = (the number of member (newMember) > 0)
if memberExists then
newMember = member (newMember)
else
return #memberInexistant
end if
otherwise
return #invalidType
end case
case newMember.type of
#text, #field: -- do nothing
otherwise
return #invalidMemberType
end case
-- End of error check
case ilk (currentMemberOrSprite) of
#sprite: if currentMemberOrSprite <> myScrolledSprite then exit
#member: if currentMemberOrSprite <> myScrolledMember then exit
-- otherwise ignore currentMemberOrSprite
end case
myScrolledMember = newMember
idealRect = myRect
if myScrolledMember.type = #field then
hBorder = myScrolledMember.border
vBorder = hBorder - (hBorder <> 0)
hMargin = myScrolledMember.margin
vMargin = hMargin / 2 --- hMargin - (hMargin mod 2)
idealRect =inflate (idealRect, -hBorder-hMargin, -hBorder-vMargin)
if myRect[1] then -- 0riginal meber had a border...
if hBorder then -- ... and so does this member
idealRect[1] = idealRect[1] - 1
end if
else -- Original member had NO border...
if hBorder then -- ... but this one has.
idealRect[1] = idealRect[1] - 1
end if
end if
end if
myScrolledMember.rect = idealRect
myScrolledSprite.member = myScrolledMember
myScrolledMember.boxType = #fixed
i = ourControlList.count()
repeat while i
call (#NewMember, ourControlList[i])
i = i - 1
end repeat
updateStage
call (#InstallElement, ourControlList.dragger)
end CustomScrollbar_SwapMember
on CustomScrollbar_GetReference me, memberOrSprite, controlOrList
-- Returns a reference to the behavior for Lingo calls.
-- The parameters are optional: use them to find a specific behavior.
-- Use 'theElement' to find the scrollbar of a particular sprite or member
-- Use 'controlOrList' to find a specific behavior (up|downArrow|dragger|bar)
-- or to return a property list of all behaviors.
-- Examples:
--
-- put sendAllSprites (#CustomScrollbar_GetReference, sprite 1, #dragger)
-- -- <offspring "Custom Scrollbar" 3 486bc20>
--
-- put sendAllSprites (#CustomScrollbar_GetReference, sprite 1, [:])
-- -- #bar: <ref>, #upArrow: <ref>, #dragger: <ref>, #downArrow: <ref>]
--
-- You can leave the controlOrList parameter empty. If you do, the
-- behavior reference on the highest sprite in the scrollbar will be returned.
case ilk (memberOrSprite) of
#sprite: if memberOrSprite <> myScrolledSprite then exit
#member: if memberOrSprite <> myScrolledMember then exit
otherwise
exit
end case
if not voidP (controlOrList) then
if ilk (controlOrList) = #propList then
controlOrList.addProp(myScrollRole, me)
return controlOrList
else
if controlOrList = myScrollRole then return me
end if
else
return me
end if
end CustomScrollbar_GetReference
-- INTER-SPRITE COMMUNICATION --
-- (responses to #sendAllSprites) --
on CustomScrollbar_RollCall me, scrolledElement, controlList, maxScrollList
-- sent on StartInstallation by this and other sprites with the same behavior
if scrolledElement <> ourScrolledElement then exit
ourControlList = controlList
ourControlList.addProp(myScrollRole, me)
ourMaxScroll = maxScrollList
end CustomScrollbar_RollCall
-- (responses to #call) --
on SpriteHeight me
-- Called by InstallElement in behaviors on the bar and the dragger
-- Dealt with by behavior on the upArrow
return mySprite.height
end
on SpriteWidth me
-- Called by InstallElement in behaviors on the bar and the dragger
-- Dealt with by behavior on the upArrow
return mySprite.width
end
on GetDraggerData me
-- Called by StartScroll, MoveBar in behavior on the bar
-- Dealt with by behavior on the dragger
return [#top: mySprite.top, #bottom: mySprite.bottom]
end
on NewMember me -- sent by _SwapMember from the behavior that received the call
myScrolledMember = myScrolledSprite.member
end NewMember
-- ERROR CHECKING --
on ErrorAlert me, theError, data
-- sent by getPropertyDescriptionList, StartInstallation
case theError of
#getPDLError:
permittedTypes = PermittedMemberTypes(me)
alert "¼
Error: This behavior works only with the following member types: "&¼
permittedTypes&RETURN&RETURN&"¼
Hit OK and then delete this behavior from the sprite."&RETURN&"¼
For more information on deleting Behaviors, see the Help system."
if the optionDown then
return ¼
[ ¼
#getPDLError: ¼
[ ¼
#comment: "ERROR: Click 'Cancel'. Wrong member type.", ¼
#format: #string, ¼
#range: [""], ¼
#default: "" ¼
] ¼
]
end if
#noScrollableSprites:
alert "¼
Error: Please place a Field or Text member on the Stage before using this ¼
behavior to create a scroll bar."&RETURN&RETURN&"¼
Hit OK and then delete this behavior from the sprite."&RETURN&"¼
For more information on deleting Behaviors, see the Help system."
if the optionDown then
return ¼
[ ¼
#getPDLError: ¼
[ ¼
#comment: "ERROR: Click 'Cancel'. Place a Text or Field"&RETURN&¼
"member on Stage before creating scroll bar.", ¼
#format: #string, ¼
#range: [""], ¼
#default: "" ¼
] ¼
]
end if
otherwise
-- Determine the behavior's name
behaviorName = string (me)
delete word 1 of behaviorName
delete the last word of behaviorName
delete the last word of behaviorName
-- Convert #data to useful value
case data.ilk of
#void: data = "<void>"
#symbol: data = "#"&data
end case
if theError <> #getPDL_Invalid then
-- Determine the name and type of myScrolledMember
memberName = myScrolledMember.name
if memberName = EMPTY then
memberName = myScrolledMember
else
memberName = QUOTE&memberName"E
end if
memberName = myScrolledMember.type&&memberName
end if
case theError of
#getPDL_Invalid:
alert "¼
BEHAVIOR ERROR: Frame "&the frame&", Sprite "&me.spriteNum&RETURN&RETURN&"¼
Parameters for the "&behaviorName&"behavior have not been set."&RETURN&RETURN&"¼
Please reopen the Behavior Parameters dialog and choose again."
halt
#notScrollable:
alert "¼
BEHAVIOR ERROR: Frame "&the frame&", Sprite "&me.spriteNum&RETURN&"¼
Behavior "&behaviorName&RETURN&RETURN&"¼
Sprite "&myScrolledSprite.spriteNum&" does not ¼
contain a Field or Text member."&RETURN&"¼
Choose again in the Behavior Parameters dialog."&¼
RETURN&RETURN&"¼
Member type = "&data
halt
#extraControl:
if the runMode = "Author" then
alert "¼
BEHAVIOR ERROR: Frame "&the frame&", Sprite "&me.spriteNum&RETURN&"¼
Behavior "&behaviorName&RETURN&RETURN&"¼
There is more than one "&data&" sprite defined for the scroll bar for ¼
sprite "&myScrolledSprite.spriteNum&", "&memberName&"."
end if
#missingControls:
alert "¼
BEHAVIOR ERROR: Frame "&the frame&", Sprite "&me.spriteNum&RETURN&"¼
Behavior "&behaviorName&RETURN&RETURN&"¼
The following elements of the scroll bar for sprite "&¼
myScrolledSprite.spriteNum&", "&memberName&" are missing:"&RETURN&RETURN&¼
data
halt
end case
end case
end ErrorAlert
-- AUTHOR-DEFINED PARAMETERS --
on getPropertyDescriptionList me
if not the currentSpriteNum then exit
-- Error check: does current sprite contain appropriate member type?
theMember = sprite(the currentSpriteNum).member
memberType = theMember.type
permittedTypes = PermittedMemberTypes(me)
if not permittedTypes.getPos(memberType) then
return ErrorAlert (me, #getPDLError, permittedTypes)
end if
-- Find sprites with field or text members
scrollableList = GetScrollableSprites (me)
if not scrollableList.count then
return ErrorAlert (me, #noScrollableSprites)
end if
return ¼
[ ¼
#myScrollRole: ¼
[ ¼
#comment: "Current sprite acts as:", ¼
#format: #symbol, ¼
#range: [#upArrow, #downArrow, #dragger, #bar], ¼
#default: 1 ¼
], ¼
#ourScrolledElement: ¼
[ ¼
#comment: "Scroll the member of", ¼
#format: #string, ¼
#range: scrollableList, ¼
#default: scrollableList[1] ¼
], ¼
#myStandardMember: ¼
[ ¼
#comment: "Standard member:", ¼
#format: #graphic, ¼
#default: theMember ¼
], ¼
#myActiveMember: ¼
[ ¼
#comment: "(Arrows only) mouseDown member:", ¼
#format: #graphic, ¼
#default: theMember ¼
], ¼
#myMultiThreading: ¼
[ ¼
#comment: "Allow animations to continue (slower)?", ¼
#format: #boolean, ¼
#default: TRUE ¼
] ¼
]
end getPropertyDescriptionList
on GetScrollableSprites me, permittedTypes
-- Returns a list of sprites containing Field or Text members, in the format:
-- ["<spriteNumber>, <type> <member.name|member>",...]
scrollableSprites = []
repeat with theSprite = 1 to the lastChannel
theMember = sprite(theSprite).member
case theMember.type of
#field, #text:
memberName = theMember.name
if memberName = EMPTY then
memberName = theMember
else
memberName = QUOTE&memberName"E
end if
memberName = theMember.type&&memberName
scrollableSprites.append ("sprite "&theSprite&": "&memberName)
end case
end repeat
return scrollableSprites
end GetScrollableSprites
on PermittedMemberTypes me
-- sent by:
-- getBehaviorDescription
-- getPropertyDescriptionList
-- ErrorAlert
return [#animgif, #bitmap, #filmLoop, #flash, #movie, #picture, #shape]
end PermittedMemberTypes